home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1997 / MacHack 1997.toast / Hacks / Hacks ’96 / Venus / SimpleWindow.cc < prev    next >
Text File  |  1996-06-22  |  14KB  |  438 lines

  1. /*
  2.  ***********************************************************************
  3.  *
  4.  *                    Simple Window Class
  5.  *    A generic simple window that can be dragged around the screen
  6.  *        and closed by clicking a "go-away" button
  7.  * No other events are handled, redefine the event handler if necessary.
  8.  *        
  9.  *
  10.  ***********************************************************************
  11.  */
  12.  
  13. #include "image.h"
  14. #include "mymenv.h"
  15. #include "window.h"
  16. //#include <PictUtil.h>
  17.  
  18. /*
  19.  *----------------------------------------------------------------------
  20.  *                Service functions
  21.  */
  22.  
  23.                 // Getting a bounding rectangle of an image
  24. ScreenRect::ScreenRect(const IMAGE& image)
  25. {
  26.   left = top = 0;
  27.   right = image.q_ncols();
  28.   bottom = image.q_nrows();
  29. }
  30.  
  31. #if 0
  32.  
  33.                 // Create a rectangle of given height/width
  34.                 // positioned at the origin
  35. ScreenRect::ScreenRect(const rowcol& heightwidth)
  36. {
  37.   left = top = 0;
  38.   bottom = heightwidth.row();
  39.   right  = heightwidth.col();
  40. }
  41.  
  42.                     // Create a rectangle of given height/width
  43.                     // positioned at a given point
  44. ScreenRect::ScreenRect(const rowcol& origin, const rowcol& heightwidth)
  45. {
  46.   top  = origin.row();
  47.   left = origin.col();
  48.   bottom = top+heightwidth.row();
  49.   right  = left+heightwidth.col();
  50. }
  51. #endif
  52.  
  53.  
  54.                     // Shifting a rectangle by the same amount
  55.                     // in X and Y
  56. ScreenRect& ScreenRect::operator += (const int offset)
  57.   top += offset; bottom += offset; left += offset; right += offset;
  58.   return *this;
  59. }
  60.  
  61.  
  62.                     // Print what rectangle is this
  63. void ScreenRect::print(const char * title) const
  64. {
  65.   alert("Rectangle %s (%d,%d) - (%d,%d)",title,top,left,bottom,right);
  66. }
  67.  
  68.  
  69. #if 0
  70. /*
  71.  *----------------------------------------------------------------------
  72.  *                 Primitive Window creators/destructors
  73.  */
  74.  
  75.                         // This is a protected constructor. Normally
  76.                         // objects XVTBasicWindow are created as a part
  77.                         // of a derived class
  78. XVTBasicWindow::XVTBasicWindow(void)
  79. {
  80.   Not_canceled = FALSE;
  81.   this_window = NULL_WIN;
  82. }
  83.  
  84.                         // Destroy the window if it hasn't been destroyed
  85.                         // already
  86. XVTBasicWindow::~XVTBasicWindow(void)
  87. {
  88.   if( this_window != 0 )
  89.     close_window(this_window);
  90. }
  91.  
  92.                         // Close the window
  93. void XVTBasicWindow::cancel(void)
  94. {
  95.   Not_canceled = FALSE;
  96.   if( this_window != 0 )
  97.     close_window(this_window);
  98. }
  99.  
  100. /*
  101.  *----------------------------------------------------------------------
  102.  *                   Basic event dispatching/handling
  103.  */
  104.  
  105.                         // A universal event handler: does almost nothing
  106.                         // but watches creation and destruction of windows
  107.                         // (to tell when there are no windows to watch)
  108.                         // For any other tasks, it calls the handler of
  109.                         // a particular window
  110. int XVTBasicWindow::no_opened_windows = 0;
  111. long XVTBasicWindow::universal_handler(WINDOW win, EVENT *ep)
  112.  
  113. {
  114.   XVTBasicWindow& the_window = *(XVTBasicWindow *)get_app_data(win);
  115.  
  116.   if( ep->type == E_CREATE )
  117.     no_opened_windows++, the_window.this_window = win;
  118.  
  119.   the_window.handler(*ep);
  120.  
  121.                                 // XVT would destroy the window after this
  122.                                 // event
  123.   if( ep->type == E_DESTROY )
  124.     no_opened_windows--, the_window.this_window = 0;
  125.  
  126.   return 0;
  127. }
  128.  
  129.                                 // Serve the windows until all get closed
  130. void XVTBasicWindow::serve_to_death(void)
  131. {
  132.   while( no_opened_windows>0 )
  133.     process_events();
  134. }
  135.  
  136.  
  137.                         // Event handler for a particular window
  138.                         // Finally, a handler which really does smth
  139.                         // specific
  140. void XVTBasicWindow::handler(EVENT event)
  141. {
  142.   switch(event.type)
  143.   {
  144.     case E_CREATE:
  145.          if( !initialize() )
  146.            cancel();
  147.          break;
  148.   }
  149. }
  150.  
  151. /*
  152.  *----------------------------------------------------------------------
  153.  *                              Window creators
  154.  *
  155.  * Note, event processing may start *before* the create_* functions return!
  156.  * So, if initialize() or event handlers, etc rely on some data that are
  157.  * going to be initialized *after* create_* function, you're in trouble!
  158.  * It's better to call create() function the last thing in the constructor,
  159.  * or even not to call at all (call it separetely later) to allow derived
  160.  * classes initialize properly!
  161.  *
  162.  */
  163. #endif
  164.  
  165. /*
  166.  *----------------------------------------------------------------------
  167.  *                              Window creators
  168.  */
  169.  
  170.                 // Create a color window of the specified size and title
  171.                 // Note, the upper left corner of 'rect' must
  172.                 // NOT be (0,0)!
  173. ScreenWindow::ScreenWindow(ScreenRect rect, const char * title)
  174. {
  175.   const int window_offset = 100;        // Cannot be 0 or small!
  176.   this_window = NewCWindow(nil,rect += window_offset,(Pstr)title,
  177.                TRUE,noGrowDocProc,
  178.                (WindowPtr)(-1),TRUE,(long)this);
  179.   assert( this_window != 0 );
  180.   SetPort(this_window);
  181.   SelectWindow(this_window);
  182. }
  183.  
  184.                 // Create a color window from a resource template
  185. ScreenWindow::ScreenWindow(const short resource_id)
  186. {
  187.   this_window = GetNewCWindow(resource_id,nil,(WindowPtr)(-1));
  188.   SetWRefCon(this_window,(long)this);
  189.   assert( this_window != 0 );
  190.   SetPort(this_window);
  191.   SelectWindow(this_window);
  192. }
  193.  
  194.  
  195.             // I wouldn't've needed this is destructor had been really virtual. Right now,
  196.             // CW 6.0 accepts attribute virtual for the destructor, but doesn't override
  197.             // destructors as it does for virtual functions. Oh, well, another kludge
  198.  
  199.                             // Close the window and clean up the rubble
  200. void ScreenWindow::destroy_it(void)
  201. {
  202.   assert( this_window != 0 );
  203.   DisposeWindow(this_window);
  204.   this_window = 0;
  205. }
  206.  
  207. /*
  208.  *----------------------------------------------------------------------
  209.  *                           Basic Even Handling
  210.  */
  211.  
  212.                 // Top-level event dispatcher
  213.                 // Returns FALSE when the window is to be destroyed
  214.                 // and won't need any further events
  215. Boolean ScreenWindow::handle_event(const EventRecord& the_event)
  216. {
  217.   switch( the_event.what )
  218.   {
  219.     case mouseDown:
  220.          WindowPtr    wp;
  221.          short        windowPart = FindWindow(the_event.where, &wp);
  222.          if( !handle_mouse_down(the_event,wp,windowPart) )
  223.            return FALSE;        // Window is to be closed (go-away buttin clicked)
  224.          break;
  225.             
  226.     case updateEvt:
  227.          if( this_window == (WindowPtr)the_event.message )
  228.            update();
  229.          break;
  230.  
  231.     case keyDown:
  232.     case autoKey:
  233.          if( !handle_key_down(the_event) )
  234.            return FALSE;        // a "quit" key must've been pressed
  235.          break;
  236.                         
  237.     case activateEvt:
  238.          if( this_window == (WindowPtr)the_event.message )
  239.            if( the_event.modifiers & 0x01 )
  240.              SetPort(this_window);
  241.   }
  242.   return TRUE;
  243. }
  244.  
  245.                 // Handle "mouse-down" events
  246.                 // Returns FALSE if the user clicked within the
  247.                 // go-away region of our window. Otherwise,
  248.                 // returns TRUE
  249.                 // Handles dragging if necessary and system clicks
  250. Boolean ScreenWindow::handle_mouse_down
  251.     (const EventRecord& the_event, WindowPtr where_window, short window_part)
  252. {
  253.   switch( window_part )
  254.   {
  255.     case inSysWindow: 
  256.          SystemClick(&the_event, where_window);
  257.      break;
  258.         
  259.     case inMenuBar:
  260.          break;                // Don't handle it yet
  261.  
  262.     case inContent:
  263.          break;
  264.           
  265.     case inDrag:
  266.          if( this_window == where_window )
  267.            DragWindow(this_window,the_event.where,&qd.screenBits.bounds);
  268.          break;
  269.                       
  270.     case inGoAway:
  271.          return !TrackGoAway(where_window, the_event.where);
  272.   }
  273.   return TRUE;
  274. }
  275.  
  276.                 // Handles key_down & auto_key events. Return FALSE
  277.                 // if the window is to be closed down
  278. Boolean ScreenWindow::handle_key_down(const EventRecord& the_event)
  279. {
  280.   return FALSE;                // Any key kills the application, sorry
  281. }
  282.  
  283.  
  284.                 // Handles null events, when nothing happens for some
  285.                 // time. Return FALSE when it's time to die
  286. Boolean ScreenWindow::handle_null_event(const long event_time)
  287. {
  288.   return TRUE;                            // Keep going
  289. }
  290.  
  291.  
  292.  
  293.             // Private window parts
  294.                 // Handle an update event - redraw the window
  295.                 // A virtual function draw() is called to do
  296.                 // the actual redrawing
  297. void ScreenWindow::update(void)
  298. {
  299.   SetNewGrafPtr((GrafPtr)this_window);
  300.   BeginUpdate(this_window);
  301.   draw();
  302.   EndUpdate(this_window);
  303. }
  304.  
  305.                 // Make the entire window being redrawn
  306. void ScreenWindow::refresh(void)
  307. {
  308.   InvalRect(&this_window->portRect);            
  309. }
  310.  
  311.  
  312. /*
  313.  *----------------------------------------------------------------------
  314.  *                An off-screen pixel buffer for faster drawing
  315.  */
  316.  
  317.                     // Allocate the buffer for offscreen
  318.                     // drawing and load a CLUT (if clut_id != 0)
  319. OffScreenBuffer::OffScreenBuffer(ScreenRect rect, const short clut_id)
  320.     : graf_world(nil)
  321. {
  322.   CTabHandle clut_handle = nil;
  323.   if( clut_id != 0 )
  324.   {                                        // try to get a user CLUT with that resource id
  325.     clut_handle = GetCTable(clut_id);
  326.     assert( clut_handle != 0 );
  327.   }
  328.   do_well( NewGWorld(&graf_world,8,rect,clut_handle,nil,0) );
  329.   assert( graf_world != nil );
  330.  
  331.   if( clut_handle != nil )
  332.     DisposCTable(clut_handle);        // CLUT has been copied, and can be disposed of now
  333.  
  334.                     // Get hold of the offscreen pixmap
  335.   pixmap = GetGWorldPixMap(graf_world);            // and make sure it looks like
  336.   assert( pixmap != nil && *pixmap != nil );    // we can use it
  337.  
  338.   assert( (**pixmap).cmpCount == 1 );            // We have a color table index
  339.   assert( !PixMap32Bit(pixmap) );
  340.  
  341.   _height = abs((**pixmap).bounds.top - (**pixmap).bounds.bottom);
  342.   _width  = abs((**pixmap).bounds.right - (**pixmap).bounds.left);
  343.   _bytes_per_row = (**pixmap).rowBytes & 0x7fff;
  344.  
  345.   assert( _height > 0 && _height < 10000 );         // Just to play safe
  346.   assert( _width > 0 && _width <= _bytes_per_row );    
  347. }
  348.  
  349.                     // Dispose of the offscreen buffer
  350. OffScreenBuffer::~OffScreenBuffer(void)
  351. {
  352.   assert( graf_world != nil );
  353.   DisposeGWorld(graf_world);
  354.   graf_world = nil;
  355. #if 0
  356.   PaletteHandle window_palette = GetPalette(our_window());
  357.   if( window_palette != nil )        // dispose of our palette if was allocated
  358.   {
  359.     SetPalette(our_window(),nil,FALSE);
  360.     DisposePalette(window_palette);
  361.   }
  362. #endif
  363.   pixmap = nil;
  364.   _height = _width = _bytes_per_row = 0;
  365. }
  366.  
  367. #if 0
  368.             // Make sure that the colors of our off-screen
  369.             // buffer would be displayed properly (or close enough)
  370.             // on screen
  371. void OffScreenBuffer::activate_palette(void)
  372. {
  373.   CTabHandle window_ctab = (**pixmap).pmTable;
  374.   assert( window_ctab != nil && *window_ctab != nil );
  375.  
  376.   PaletteHandle palette = NewPalette((**window_ctab).ctSize,window_ctab,pmTolerant+pmExplicit,0);
  377.   assert( palette != nil );
  378.   SetPalette(our_window(),palette,TRUE);
  379.   do_well( QDError() );
  380.   ActivatePalette(our_window());    
  381.   do_well( QDError() );
  382. }
  383. #endif
  384.  
  385.  
  386.                 // Actual drawing - moving the picture from the
  387.                 // offscreen grafworld to the onscreen one, to the current port.
  388.                 // Remember to set a device to that of the offscreen
  389.                 // grafworld before CopyBits (in order to get grafworld's color table and 
  390.                 // inverse color table to be used): see IM, Palette Manager
  391.                 // Also note, if a window we're going to draw on is partly/completely
  392.                 // obscured, then the visRgn, the visible region of the on-screen window,
  393.                 // is *not* a window rectangle. When we make the offscreen grafworld the
  394.                 // current grafport for CopyBits, CopyBits has no way of knowing then that
  395.                 // the true destination region may not be the whole where_rect at all. To make
  396.                 // CopyBits aware of the fact that the onscreen window maybe abscured, we
  397.                 // pass the visRgn of the onscreen window as a clipping region to CopyBits.
  398.                 // In that case CopyBits performs clipping just as if the onscreen window
  399.                 // where the current grafport.
  400.                 // Note, to be really precise, we ought to pass CopyBits() an intersection of
  401.                 // onscreen grafport's visRgn and clipRgn. Well, we take a shortcut here:
  402.                 // normally clipRgn is set to be the whole screen. Moreover, visRgn is clipped
  403.                 // already not only to the unobscured part of the window, but to the update
  404.                 // region as well. So using visRgn only should suffice....
  405.                 // Also make sure that the onscreen window has a palette roughly corresponding
  406.                 // to the CLUT of the grafworld (otherwise colors would be screwed up)
  407.                 // One can use a palette resource 0 to be used as a default palette for
  408.                 // dialogs/windows within the task
  409.                 
  410.                 // Note there is a different way to force color translation when drawing a picture
  411.                 // (seems to work better in 68k universe). One needs to create a grafworld, and
  412.                 // and draw on it within OpenPicture()...ClosePicture(). Then one can draw
  413.                 // thus recorded picture on the current window. The colors seem to get translated
  414.                 // correctly, and one doesn't need to worry about clipping, etc (as in the method
  415.                 // way explained above). One can use this technique to force 24->8 color
  416.                 // translation (with dithering) if the grafworld was created as 24-bit.
  417.  
  418. void OffScreenBuffer::draw(const Rect& where_rect, const Rect& from_rect)
  419. {
  420. //  const BitMap * where_pixmap = &qd.thePort->portBits;    // see below
  421.   CGrafPtr old_port;
  422.   GDHandle old_gdevice;
  423.   GetGWorld(&old_port,&old_gdevice);
  424.   const RgnHandle where_visible_region = old_port->visRgn;
  425.   SetGWorld((CGrafPtr)graf_world,nil);
  426.                                                   // The following line is actually the same as
  427.                                                   // the one commented at the very top. However,
  428.                                                   // thePort stuff doesn't work under OpenDoc, but
  429.                                                   // the following line does.
  430.   const BitMap * where_pixmap = &((GrafPtr)old_port)->portBits;
  431.   //!!!Set_NewGrafWorld((GWorldPtr)graf_world);    // Doesn't work: CW disposes of the object too early
  432.   assert( LockPixels(pixmap) );
  433.   CopyBits((const BitMap *)*pixmap, where_pixmap, &from_rect, &where_rect, /*ditherCopy*/ srcCopy, where_visible_region);
  434.   SetGWorld(old_port,old_gdevice);
  435.   UnlockPixels(pixmap);
  436. }
  437.